package com.gitee.wsl.common.chart.sample.pie

import android.graphics.*
import com.gitee.wsl.android.ext.base.getForegroundColorForBackgroundColor
import com.gitee.wsl.android.ext.math.calcArcEndPointXY
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.adapter.DataSource
import com.gitee.wsl.common.chart.adapter.SelectItemChartAdapter
import com.gitee.wsl.common.chart.listener.click.ArcPosition
import com.gitee.wsl.common.chart.listener.click.PlotArcPosition
import com.gitee.wsl.common.chart.model.PlotDot
import com.gitee.wsl.common.chart.render.foreground.info.PlotLegendItem
import com.gitee.wsl.common.chart.model.PlotArcLabelInfo
import com.gitee.wsl.common.chart.sample.AbstractCirChart
import com.gitee.wsl.common.chart.sample.pie.adapter.PieChartAdapter
import com.gitee.wsl.common.chart.sample.pie.model.PieData
import com.gitee.wsl.common.ui.draw.type.DotStyle
import com.gitee.wsl.ext.base.ColorExt
import com.gitee.wsl.math.Math
import com.gitee.wsl.jvm.math.add
import com.gitee.wsl.jvm.math.div
import com.gitee.wsl.jvm.math.sub
import com.gitee.wsl.math.getSliceAngle


import timber.log.Timber

/**
 * @ClassName PieChart
 * @Description  饼图基类
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */
open class PieChart(val adapter:PieChartAdapter = PieChartAdapter()): AbstractCirChart(adapter),
    SelectItemChartAdapter<PieData> by adapter{
    //数据源
    var dataSet by DataSource(adapter)

    //是否使用渲染来突出效果
    var gradient = true

    //选中区偏移分离长度
    var selectedOffset = 10.0f

    val arcPaint: Paint = Paint().apply { isAntiAlias=true }

    val rectF: RectF = RectF()

    //扇形边框
    val arcBorderPaint: Paint by lazy {
          Paint(Paint.ANTI_ALIAS_FLAG).apply {
              style = Paint.Style.STROKE
              color = Color.WHITE
         }
    }

    //是否需要保存标签的位置
    var isSaveLabelsPosition = false
    var labelSaveType = ChartEnum.LabelSaveType.ONLYPOSITION

    //保存标签的坐标信息
    val lstLabels = mutableListOf<PlotArcLabelInfo>()

    //总角度
    var totalAngle = 360f


    /**
     * 是否保存标签显示位置并设置标签信息的保存类型 <br></br>
     * ONLYPOSITION : 保存坐标信息，但不显示标签 <br></br>
     * ALL : 保存坐标信息，也显示标签 <br></br>
     * 用来在其上绘图片之类操作 <br></br>
     * @param type 类型
     */
    fun saveLabelsPosition(type: ChartEnum.LabelSaveType) {
        labelSaveType = type
        isSaveLabelsPosition = ChartEnum.LabelSaveType.NONE != type
    }

    /**
     * 给画笔设置渲染颜色和效果
     * @param paintArc    画笔
     * @param cirX        中心点X坐标
     * @param cirY        中心点Y坐标
     * @param radius    半径
     * @return    返回渲染效果类
     */
    private fun drawRadialGradient(
        paintArc: Paint,
        cirX: Float,
        cirY: Float,
        radius: Float
    ): RadialGradient {
        val radialRadius = radius * 0.8f
        val color = paintArc.color
        val darkerColor = ColorExt.getForegroundColorForBackgroundColor(color)

        //返回环形渐变
        return RadialGradient(
            cirX, cirY, radialRadius,
            darkerColor, color,
            Shader.TileMode.MIRROR
        )
    }

    /**
     * 检查角度的合法性
     * @param Angle 角度
     * @return 是否正常
     */
    protected fun validateAngle(Angle: Float): Boolean {
        return !(Angle.compareTo(0.0f) == 0 || Angle.compareTo(0.0f) == -1)
    }

    protected fun drawArcBorder(
        canvas: Canvas, rect: RectF,
        offsetAngle: Float, currentAngle: Float
    ) {
        //边框
        canvas.drawArc(rect, offsetAngle, currentAngle, true, arcBorderPaint)
    }

    protected fun initRectF(left: Float, top: Float, right: Float, bottom: Float) {
         rectF[left, top, right] = bottom
    }

    protected fun drawLabels(canvas: Canvas): Boolean {
        var showLabel = true
        if (isSaveLabelsPosition) {
            if (ChartEnum.LabelSaveType.ONLYPOSITION == labelSaveType) showLabel = false
        }
        val count = lstLabels.size
        for (i in 0 until count) {
            val info = lstLabels[i]
            drawLabel(canvas, dataSet[info.id], info, isSaveLabelsPosition, showLabel)
        }
        if (!isSaveLabelsPosition) lstLabels.clear()
        return true
    }

    /**
     * 绘制图
     */
    protected open fun drawPlot(canvas: Canvas): Boolean {
        try {
            //中心点坐标
            val cirX: Float = bodyViewport.centerX
            val cirY: Float = bodyViewport.centerY
            val radius: Float = radius
            if (radius.compareTo(0.0f) == 0 || radius.compareTo(0.0f) == -1) {
                return false
            }

            //用于存放当前百分比的圆心角度
            var currentAngle = 0.0f
            var offsetAngle = offsetAngle
            lstLabels.clear()
            val left: Float = Math.sub(cirX, radius)
            val top: Float = Math.sub(cirY, radius)
            val right: Float = Math.add(cirX, radius)
            val bottom: Float = Math.add(cirY, radius)
            val count = dataSet.size
            for (i in 0 until count) {
                val cData = dataSet[i]
                //currentAngle = cData.getSliceAngle();
                currentAngle = Math.getSliceAngle(totalAngle, cData.percentage)
                if (!validateAngle(currentAngle)) continue
                arcPaint.color = cData.sliceColor

                // 绘制环形渐变
                if (gradient) arcPaint.shader = drawRadialGradient(
                    arcPaint,
                    cirX,
                    cirY,
                    radius
                )
                if (cData.isSelected) //指定突出哪个块
                {
                    //偏移圆心点位置(默认偏移半径的1/10)
                    val newRadius: Float = Math.div(radius, selectedOffset)

                    //计算百分比标签
                    val point = Math.calcArcEndPointXY(
                        cirX, cirY,
                        newRadius,
                        Math.add(offsetAngle, currentAngle / 2f)
                    )
                    initRectF(
                        Math.sub(point.x, radius), Math.sub(point.y, radius),
                        Math.add(point.x, radius), Math.add(point.y, radius)
                    )
                    lstLabels.add(PlotArcLabelInfo(i, point.x, point.y, radius, offsetAngle, currentAngle))
                } else {
                    initRectF(left, top, right, bottom)
                    lstLabels.add(PlotArcLabelInfo(i, cirX, cirY, radius, offsetAngle, currentAngle))
                }

                //在饼图中显示所占比例
                canvas.drawArc(rectF, offsetAngle, currentAngle, true, arcPaint)

                //边框
                drawArcBorder(canvas, rectF, offsetAngle, currentAngle)

                //保存角度

                  saveArcRecord(
                      i, cirX + translateXY[0], cirY + translateXY[1],
                      radius, offsetAngle, currentAngle,
                      selectedOffset, this.offsetAngle
                  )

                //下次的起始角度
                offsetAngle = Math.add(offsetAngle, currentAngle)
            }

            adapter.isRecordSetInited = true

            //绘制Label
            drawLabels(canvas)

            //图KEY
            //plotLegend.renderPieKey(canvas, mDataset)
            //renderLegend(canvas, mDataset)
        } catch (e: Exception) {
            Timber.d(e)
            return false
        }
        return true
    }

    /*fun renderLegend(canvas: Canvas, dataSet: List<PieData>){
        var key = ""
        val legendList= mutableListOf<LegendItem>()
        for (cData in dataSet) {

            key = cData.mPieKey

            if (key.isEmpty()) continue

            val dot = PlotDot()
            dot.dotStyle = DrawEnum.DotStyle.RECT

            legendList.add(LegendItem(key,cData.sliceColor,dot))
        }

        plotLegend.renderInfo(canvas,legendList)
    }*/

    override fun createLegendData(): List<PlotLegendItem> {
        var key = ""
        val legendList= mutableListOf<PlotLegendItem>()
        for (cData in dataSet) {

            key = cData.pieKey

            if (key.isEmpty()) continue

            val dot = PlotDot()
            dot.dotStyle = DotStyle.RECT

            legendList.add(PlotLegendItem(key,cData.sliceColor,dot))
        }
        return legendList
    }

    /**
     * 检验传入参数,累加不能超过360度
     * @return 是否通过效验
     */
    protected fun validateParams(): Boolean {
        var totalAngle = 0.0f
        var currentValue = 0.0f
        for (cData in dataSet) {
            //currentValue = cData.getSliceAngle();
            currentValue = Math.getSliceAngle(this.totalAngle, cData.percentage)
            totalAngle = Math.add(totalAngle, currentValue)
            //Log.e(TAG,"圆心角:"+Float.toString(currentValue)+" 合计:"+Float.toString(totalAngle));
            if (totalAngle.compareTo(0.0f) == -1) {
               Timber.d( "传入参数不合理，圆心角总计小于等于0度. 现有圆心角合计:$totalAngle 当前圆心角:$currentValue 当前百分比:${cData.percentage}")
                //return false;
            } else if (totalAngle.compareTo(this.totalAngle + 0.5f) == 1) {
                //圆心角总计大于360度
                Timber.d( "传入参数不合理，圆心角总计大于总角度. 现有圆心角合计:$totalAngle" )
                //return false;
            }
        }
        return true
    }

    /**
     * 返回当前点击点的信息
     * @param x 点击点X坐标
     * @param y    点击点Y坐标
     * @return 返回对应的位置记录
     */
    fun getPositionRecord(x: Float, y: Float): ArcPosition? {
        return selectHelper?.getArcRecord(x, y)
    }
    
    override fun renderBody(canvas: Canvas): Boolean {
            super.renderBody(canvas)

            //检查值是否合理
            if (!validateParams()) return false

            //绘制图表
            drawPlot(canvas)

            /*//显示焦点
            drawFocusShape(canvas)
            //响应提示
            drawToolTip(canvas)*/
        return true
    }

    /**
     * 绘制焦点形状
     *
     * @param canvas
     *            画布
     * @return 是否绘制成功
     */
    override fun drawFocusShape(canvas:Canvas){
        //selectHelper?.renderFocusShape(canvas)
       /* adapter.selectRecordSet.forEach {focusArcPosition->
            val pointCir = focusArcPosition.pointF
            var cirX = pointCir!!.x
            var cirY = pointCir.y
            val radius = focusArcPosition.radius

                // 偏移圆心点位置(默认偏移半径的1/10)
           val newRadius: Float = div(radius, focusArcPosition.selectedOffset)
                // 计算百分比标签
           val point = calcArcEndPointXY(cirX, cirY, newRadius, add(focusArcPosition.startAngle, focusArcPosition.sweepAngle / 2f))
           cirX = point.x
           cirY = point.y

            canvas.drawPercentArc(
                focusPaint,
                cirX, cirY, radius, focusArcPosition.startAngle,
                focusArcPosition.sweepAngle, true
            )
        }*/
    }

    // 保存角度 (半径)
    fun saveArcRecord(
        dataID: Int, centerX: Float, centerY: Float,
        radius: Float, offsetAngle: Float, Angle: Float, selectedOffset: Float,
        initialAngle: Float
    ) {
        //selectHelper?.saveArcRecord(dataID,centerX, centerY, radius, offsetAngle, Angle, selectedOffset, initialAngle)
        if(adapter.isRecordSetInited) return
        val pRecord = PlotArcPosition()
        pRecord.savePlotDataID(dataID)
        pRecord.savePlotCirXY(centerX, centerY)
        pRecord.saveAngle(radius, offsetAngle, Angle, selectedOffset)
        pRecord.saveInitialAngle(initialAngle)
        adapter.addRecordItem(pRecord)
    }
    
    /**
     * 绘制提示信息
     *
     * @param canvas
     * 画布
     */
    /*override fun renderToolTip(canvas: Canvas) {
        
        mToolTip.renderInfo(canvas)
    }*/
    
}